﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using SHARED;

namespace IPL
{
    public enum NodeType
    {
        Rule,
        Token
    }

    public enum TokenType
    {
        End,
        Symbol,
        Keyword,
        Identifier
    }

    public abstract class Node
    {
        public NodeType NodeType { get; set; }
        public IList<Node> Children { get; set; }

        protected Node(NodeType type)
        {
            this.NodeType = type;
        }
    }

    public class Rule : Node
    {
        public string Name { get; set; }

        public Rule(string name, NodeType type)
            : base(NodeType.Rule)
        {
            Name = name;
            NodeType = type;
        }
    }

    public abstract class Token : Node
    {
        public TokenType TokenType { get; set; }
        public string Lexem { get; set; }
        public int LineNum { get; set; }
        public string Value { get; set; }

        public Token(string lexem, int lineNum, TokenType tType)
            : base(NodeType.Token)
        {
            this.TokenType = tType;
            Lexem = lexem;
            LineNum = lineNum;
            setValue(lexem);
        }

        protected Token setValue(string value) { this.Value = value; return this; }

        public static Token New(string lexem, int lineNum)
        {
            if (Regex.IsMatch(lexem.ToLower(), @"^[=,;:*<>(){}[\]-]$")) // Symbols
            {
                return new SymbolToken(lexem, lineNum, TokenType.Symbol).setValue(lexem);
            }
            else if (Regex.IsMatch(lexem.ToLower(), @"^(select|as|from)$")) // Keywords
            {
                return new KeywordToken(lexem, lineNum, TokenType.Keyword);
            }
            else if (Regex.IsMatch(lexem.ToLower(), @"^[a-z0-9_]+(\.[a-z0-9_]+)?$")) // Identifier
            {
                return new IdentifierToken(lexem, lineNum, TokenType.Identifier);
            }
            else
            {
                throw new Exception(String.Format("No Token matching lexem \"{0}\" on line {1}", lexem, lineNum));
            }
        }
    }

    public class EndToken : Token
    {
        public EndToken(string lexem, int lineNum, TokenType tType)
            : base(lexem, lineNum, tType) { }
    }

    public class ConstantToken : Token
    {
        public ConstantToken(string lexem, int lineNum, TokenType tType)
            : base(lexem, lineNum, tType) { }
    }

    public class SymbolToken : Token
    {
        public SymbolToken(string lexem, int lineNum, TokenType tType)
            : base(lexem, lineNum, TokenType.Symbol) { }
    }

    public class KeywordToken : Token
    {
        public KeywordToken(string lexem, int lineNum, TokenType tType)
            : base(lexem, lineNum, TokenType.Keyword) { }
    }

    public class IdentifierToken : Token
    {
        public IdentifierToken(string lexem, int lineNum, TokenType tType)
            : base(lexem, lineNum, TokenType.Identifier) { }
    }

}